home *** CD-ROM | disk | FTP | other *** search
- /*
- * This program is in public domain; written by Dave G. Conroy.
- * This file contains the main driving routine for the Micro-
- * EMACS screen editor. This version began as the original
- * small version by DGC. It has been extensively expanded
- * using versions 35 (a hybrid) and 36 (a direct descendent).
- * This version includes a number of text functions that are
- * not found in others and a word wrap algorithm different from
- * 35 or 36. It also contains a kermit module, real page movement,
- * printer support and a shell command. It is sort of a cross
- * between ME and Perfect Writer version 1.03.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <osbind.h>
- #include "ed.h"
- #if ST
- #include "keycode.h"
- #endif
-
- #if VMS
- #include <ssdef.h>
- #define GOOD (SS$_NORMAL)
- #endif
-
- #ifndef GOOD
- #define GOOD 0
- #endif
-
- char *version = "v. 33 25-January-1987";
-
- int currow; /* Working cursor row */
- int curcol; /* Working cursor column */
- int fillcol = 76; /* Current fill column */
- int indcol; /* Current indent column */
- int thisflag; /* Flags, this command */
- int lastflag; /* Flags, last command */
- int curgoal; /* Goal column */
- int isnprint; /* Print buffer in use */
- int glmode = BMNWRAP; /* Begin in fundamental mode */
- BUFFER *curbp; /* Current buffer */
- WINDOW *curwp; /* Current window */
- BUFFER *bheadp; /* BUFFER listhead */
- WINDOW *wheadp; /* WINDOW listhead */
- BUFFER *blistp = NULL; /* Buffer list BUFFER */
- BUFFER *bmacrp = NULL; /* Compiled macros BUFFER */
- short kbdm[NKBDM] = CTLX|')'; /* Macro */
- short *kbdmip; /* Input for above */
- short *kbdmop; /* Output for above */
- char pat[NPAT]; /* Pattern */
- char rpat[NPAT]; /* Replacement pattern */
- char prnhdr[NPAT]; /* Print header */
- char prndate[NPAT]; /* Print date */
- char lastbuf[NBUFN]; /* Last buffer name */
- char defpath[128]; /* default path name */
- int defdrive; /* default drive */
- long buserr; /* Address of gemdos busserr */
- long adderr; /* Address of gemdos address err*/
- long progend; /* end of program after init */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- register int c;
- register int f;
- register int n;
- register int mflag;
- register int prncnt;
- register int basec;
- extern int errexit();
- extern long sbrk();
-
- #if ALCYON
- fclose(stdin); /* reduce overhead for */
- fclose(stdout); /* unused file pointers */
- fclose(stderr);
- #endif
- isnprint = FALSE;
- prncnt = 0;
-
- if (access("cc.ini",4) == NULL) /* cc drive assignments */
- commfil(FALSE,HUGE); /* and function key bind*/
- strcpy(lastbuf, "main"); /* Work out the name of */
- if (argc > 1) /* the default buffer. */
- makename(lastbuf, argv[1]);
- edinit(lastbuf); /* Buffers, windows. */
- vtinit(); /* Displays. */
- update();
- #if ST
- defdrive = Dgetdrv();
- Dgetpath(defpath,0);
- buserr = Setexc(2,-1L);
- adderr = Setexc(3,-1L);
- Setexc(2,&errexit); /* Clean up screen on err */
- Setexc(3,&errexit);
- #endif
- if (access("uemail.mcr",4) == NULL) /* default macro file */
- {
- update();
- loadmac(FALSE);
- }
- progend = sbrk(0);
- if (argc > 1) {
- update(); /* You have to update */
- readin(argv[1]); /* in case "[New file]" */
- }
- lastflag = 0; /* Fake last flags. */
- loop:
- update(); /* Fix up the screen */
-
- /* This is the print buffer code. It's very rudimentary, but it
- * works as long as the buffer in the printer does not get filled.
- * On the initial call to the function print(), the printer is
- * sent one 1536 byte buffer of data and isnprint is set to
- * TRUE. From then on the printer is sent 384 bytes of data after
- * an arbitrary number of keystrokes is entered if the printer
- * is ready.
- */
-
- if(isnprint) /* We are printing a file */
- if (prncnt++ > 16) /* Keystroke count */
- if(PRNRDY) /* Check LST: status */
- {
- prnbuf(); /* Send a buffer full */
- prncnt = 0;
- }
- f = getkey();
- if (shiftstatus == 17 || shiftstatus == 18) /* CapsLock + Shift */
- c = tolower(f);
- else
- c = f;
- if (mpresf != FALSE) {
- mlerase();
- update();
- }
- f = FALSE;
- n = 1;
-
- /* do META-# processing if needed */
-
- basec = c & ~META; /* strip meta char off if there */
- if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
- f = TRUE; /* there is a # arg */
- n = 0; /* start with a zero default */
- mflag = 1; /* current minus flag */
- c = basec; /* strip the META */
- while ((c >= '0' && c <= '9') || (c == '-')) {
- if (c == '-') {
- /* already hit a minus or digit? */
- if ((mflag == -1) || (n != 0))
- break;
- mflag = -1;
- } else {
- n = n * 10 + (c - '0');
- }
- if ((n == 0) && (mflag == -1)) /* lonely - */
- mlwrite("Arg:");
- else
- mlwrite("Arg: %d",n * mflag);
-
- c = getkey(); /* get the next key */
- }
- n = n * mflag; /* figure in the sign */
- }
-
- /* ^U expansion */
-
- if (c == (CTRL|'U')) { /* ^U, start argument */
- f = TRUE;
- n = 4; /* with argument of 4 */
- mflag = 0; /* that can be discarded. */
- mlwrite("Arg: 4");
- while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
- if (c == (CTRL|'U'))
- n = n*4;
- /*
- * If dash, and start of argument string, set arg.
- * to -1. Otherwise, insert it.
- */
- else if (c == '-') {
- if (mflag)
- break;
- n = 0;
- mflag = -1;
- }
- /*
- * If first digit entered, replace previous argument
- * with digit and set sign. Otherwise, append to arg.
- */
- else {
- if (!mflag) {
- n = 0;
- mflag = 1;
- }
- n = 10*n + c - '0';
- }
- mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
- }
- /*
- * Make arguments preceded by a minus sign negative and change
- * the special argument "^U -" to an effective "^U -1".
- */
- if (mflag == -1) {
- if (n == 0)
- n++;
- n = -n;
- }
- }
- if (c == (CTRL|'X')) { /* ^X is a prefix */
- mlwrite("C-X: ");
- c = CTLX | getctl();
- }
- if (kbdmip != NULL) { /* Save macro strokes. */
- if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
- ctrlg(FALSE, 0);
- goto loop;
- }
- if (f != FALSE) {
- *kbdmip++ = (CTRL|'U');
- *kbdmip++ = n;
- }
- *kbdmip++ = c;
- }
- execute(c, f, n); /* Do it. */
- goto loop;
- }
-
- /*
- * Initialize all of the buffers
- * and windows. The buffer name is passed down as
- * an argument, because the main routine may have been
- * told to read in a file by default, and we want the
- * buffer name to be right.
- */
- edinit(bname)
- char bname[];
- {
- register BUFFER *bp;
- register WINDOW *wp;
-
- bp = bfind(bname, TRUE, 0); /* First buffer */
- wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
- if (bp==NULL || wp==NULL)
- exit(1);
- curbp = bp; /* Make this current */
- wheadp = wp;
- curwp = wp;
- wp->w_wndp = NULL; /* Initialize window */
- wp->w_bufp = bp;
- bp->b_nwnd = 1; /* Displayed. */
- wp->w_linep = bp->b_linep;
- wp->w_dotp = bp->b_linep;
- wp->w_doto = 0;
- wp->w_markp = wp->w_dotp;
- wp->w_marko = 0;
- wp->w_toprow = 0;
- wp->w_ntrows = term.t_nrow-1; /* "-1" for mode line. */
- wp->w_force = 0;
- wp->w_flag = WFMODE|WFHARD; /* Full. */
- }
-
- /*
- * Read in a key.
- * Do the standard keyboard preprocessing.
- * Convert the keys to the internal character set. On
- * the LK201, which lacks a reasonable ESC key, make the
- * grave accent a meta key too; this is a fairly common
- * customization around Digital. Also read and decode
- * the arrow keys, and other special keys. This is
- * done in Rainbow mode; does this work on all
- * the terminals with LK201 keyboards?
- */
- getkey()
- {
- register int c;
- #if LK201
- register int n;
- loop:
- c = (*term.t_getchar)();
- if (c == AGRAVE) { /* Alternate M- prefix. */
- c = getctl();
- return (META | c);
- }
- if (c == METACH) { /* M-, or special key. */
- c = (*term.t_getchar)();
- if (c == '[') { /* Arrows and extras. */
- c = (*term.t_getchar)();
- if (c == 'A')
- return (CTRL | 'P');
- if (c == 'B')
- return (CTRL | 'N');
- if (c == 'C')
- return (CTRL | 'F');
- if (c == 'D')
- return (CTRL | 'B');
- if (c>='0' && c<='9') {
- n = 0;
- do {
- n = 10*n + c - '0';
- c = (*term.t_getchar)();
- } while (c>='0' && c<='9');
- if (c=='~' && n<=34 && (c=lkmap[n])!=0)
- return (c);
- }
- goto loop;
- }
- if (c == 'O') {
- c = (*term.t_getchar)();
- if (c == 'P') /* PF1 => M-X (Future) */
- return (META | 'X');
- if (c == 'Q') /* PF2 => C-Q */
- return (CTRL | 'Q');
- if (c == 'R') /* PF3 => C-S */
- return (CTRL | 'S');
- if (c == 'S') /* PF4 => C-R */
- return (CTRL | 'R');
- goto loop;
- }
- if (c>='a' && c<='z') /* Force to upper */
- c -= 0x20;
- if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
- c = CTRL | (c+'@');
- return (META | c);
- }
- #endif
- #if VT100
- loop:
- c = (*term.t_getchar)();
- if (c == METACH) { /* Apply M- prefix */
- c = (*term.t_getchar)();
- if (c == '[') { /* Arrow keys. */
- c = (*term.t_getchar)();
- if (c == 'A')
- return (CTRL | 'P');
- if (c == 'B')
- return (CTRL | 'N');
- if (c == 'C')
- return (CTRL | 'F');
- if (c == 'D')
- return (CTRL | 'B');
- goto loop;
- }
- if (c == 'O') {
- c = (*term.t_getchar)();
- if (c == 'P') /* PF1 => M-X (Future) */
- return (META | 'X');
- if (c == 'Q') /* PF2 => C-Q */
- return (CTRL | 'Q');
- if (c == 'R') /* PF3 => C-S */
- return (CTRL | 'S');
- if (c == 'S') /* PF4 => C-R */
- return (CTRL | 'R');
- goto loop;
- }
- if (c>='a' && c<='z') /* Force to upper */
- c -= 0x20;
- if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
- c = CTRL | (c+'@');
- return (META | c);
- }
- #endif
- c = (*term.t_getchar)();
- #if ST
- if (scancode == 0x70 && shiftstatus != 16)
- return (CTRL|'X');
- #endif
- if (c == METACH) { /* Apply M- prefix */
- mlwrite("Meta: ");
- c = getctl();
- return (META | c);
- }
- if (c == CTRLCH) { /* Apply C- prefix */
- c = getctl();
- return (CTRL | c);
- }
- if (c == CTMECH) { /* Apply C-M- prefix */
- c = getctl();
- return (CTRL | META | c);
- }
- #if ST
- /* use special keys or number pad (code >= 0x63) ?
- * 0x03 = scancode for ^@ (setmark).
- */
- if ((c == NULL && scancode != 0x03) || scancode >= 0x4a)
- if (scancode > 0x32)
- {
- /* if CapsLock and number pad, use real numbers */
- if (shiftstatus == 16 && (scancode > 0x62 ||
- scancode == 0x4a || scancode == 0x4e))
- return(c);
- else
- return (SPEC | scancode);
- }
- else {
- c = keyscan[scancode];
- return (META | c);
- }
- #endif
- if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
- c = CTRL | (c+'@');
- return (c);
- }
-
- /*
- * Get a key.
- * Apply control modifications
- * to the read key.
- */
- getctl()
- {
- register int c;
-
- c = (*term.t_getchar)();
- #if ST
- if (scancode == 0x70 && shiftstatus != 16)
- return (SPEC|'p');
- #endif
- if (c>='a' && c<='z') /* Force to upper */
- c -= 0x20;
- if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
- c = CTRL | (c+'@');
- return (c);
- }
-
- #if ST
- /* ERREXIT Since this toy insists on Bus errors for so many memory
- * accesses, we need a way to exit gracefully.
- */
- errexit()
- {
- if(mlyesno("FATAL: Buss error. Attempt to save files")!=TRUE)
- quit(TRUE,FALSE);
- quit(FALSE,FALSE);
- exit(-1);
- }
- #endif
-
- /*
- /*
- * Fancy quit command, as implemented
- * by Norm. If any buffer has changed
- * write that buffer out. Otherwise simply exit.
- */
- quickexit(f, n)
- int f, n;
- {
- register BUFFER *bp; /* for buffer scan */
-
- bp = bheadp;
- while (bp != NULL) {
- if ((bp->b_flag&BFCHG) != 0 /* Changed. */
- && (bp->b_flag&BFTEMP) == 0){ /* Real. */
- curbp = bp;
- mlwrite("[Saving %s]",bp->b_fname);
- filesave(f, n);
- }
- bp = bp->b_bufp; /* next buffer */
- }
- quit(f, n); /* conditionally quit */
- }
-
- /*
- * Quit command. If an argument, always
- * quit. Otherwise confirm if a buffer has been
- * changed and not written out. Normally bound
- * to "C-X C-C".
- */
- quit(f, n)
- int f, n;
- {
- register BUFFER *bp; /* for buffer scan */
- register int s;
-
- bp = bheadp;
- if (f != FALSE /* Argument forces it. */
- || (anycb() == FALSE /* All buffers clean. */
- && isnprint == FALSE)) { /* Are we printing? */
- vttidy();
- #if ST
- Dsetdrv(defdrive);
- Dsetpath(defpath);
- Setexc(2,buserr);
- Setexc(3,adderr);
- #endif
- exit((n!=FALSE) ? GOOD: -1);
- }
- if (isnprint)
- if ((s=mlyesno("Abandon printing")) != TRUE)
- return(s);
- while (bp != NULL) {
- if ((bp->b_flag&BFCHG) != 0 /* Changed. */
- && (bp->b_flag&BFTEMP) == 0){ /* Real. */
- curbp = bp;
- mlwrite("Save %s [y/n]?",bp->b_fname);
- switch(ttgetc()) {
- case 'Y':
- case 'y':
- filesave(f, n);
- break;
- case 0x07:
- return(ctrlg(f,n));
- default:
- break;
- }
- }
- bp = bp->b_bufp; /* next buffer */
- }
- if (anycb()) /* check once more */
- if ((s=mlyesno("Abandon modified buffers")) != TRUE)
- return(s);
- vttidy();
- #if ST
- Setexc(2,buserr);
- Setexc(3,adderr);
- #endif
- exit((n!=FALSE) ? GOOD : -1);
- }
-
- /*
- * Begin a keyboard macro.
- * Error if not at the top level
- * in keyboard processing. Set up
- * variables and return.
- */
- ctlxlp(f, n)
- int f, n;
- {
- if (kbdmip!=NULL || kbdmop!=NULL) {
- mlwrite("Not now");
- return (FALSE);
- }
- mlwrite("[Start macro]");
- kbdmip = &kbdm[0];
- return (TRUE);
- }
-
- /*
- * End keyboard macro. Check for
- * the same limit conditions as the
- * above routine. Set up the variables
- * and return to the caller.
- */
- ctlxrp(f, n)
- int f, n;
- {
- if (kbdmip == NULL) {
- mlwrite("Not now");
- return (FALSE);
- }
- mlwrite("[End macro]");
- kbdmip = NULL;
- return (TRUE);
- }
-
- /*
- * Execute a macro.
- * The command argument is the
- * number of times to loop. Quit as
- * soon as a command gets an error.
- * Return TRUE if all ok, else
- * FALSE.
- */
- ctlxe(f, n)
- register int f, n;
- {
- register int c;
- register int af;
- register int an;
- register int s;
-
- if (kbdmip!=NULL || kbdmop!=NULL) {
- mlwrite("Not now");
- return (FALSE);
- }
- if (n <= 0)
- return (TRUE);
- do {
- kbdmop = &kbdm[0];
- do {
- af = FALSE;
- an = 1;
- if ((c = *kbdmop++) == (CTRL|'U')) {
- af = TRUE;
- an = *kbdmop++;
- c = *kbdmop++;
- }
- s = TRUE;
- } while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
- kbdmop = NULL;
- } while (s==TRUE && --n);
- return (s);
- }
-
- /*
- * Abort.
- * Beep the beeper.
- * Kill off any keyboard macro,
- * etc., that is in progress.
- * Sometimes called as a routine,
- * to do general aborting of
- * stuff.
- */
- ctrlg(f, n)
- int f, n;
- {
- (*term.t_beep)();
- if (kbdmip != NULL) {
- kbdm[0] = (CTLX|')');
- kbdmip = NULL;
- }
- mlwrite("Aborting");
- return (ABORT);
- }
-
- /* CLEARFLAG clears buffer change flag. Bound to M-~
- */
- clearflag(f, n)
- register int f, n;
- {
- curwp->w_bufp->b_flag &= ~BFCHG;
- upmode();
- return(TRUE);
- }
-
- /* UNKNCOM Returns abort and beeps keyboard. Bound to unused keys.
- */
- unkncom(f, n)
- register int f, n;
- {
- mlwrite("Unbound command!");
- (*term.t_beep)();
- return(ABORT);
- }
-
- /* RETVERSION Returns version string. Bound to CTLX *.
- */
- retversion(f, n)
- register int f, n;
- {
- return(mlwrite("Writer: D. G. Conroy Revised: R. D. Royar (%s)",
- version));
- }
-